import java.util.LinkedList;

public class MaxNode extends Node {
    int alpha;

    public MaxNode(int[][] board) {
        for (int k = 0; k < 3; k++) {
            System.arraycopy(board[k], 0, this.board[k], 0, 3);
        }
        this.alpha = Game.UNKNOWN_INT;
    }

    //另一构造方法
    public MaxNode(int[][] board, int i, int j) {
        board[i][j] = -1;
        for (int k = 0; k < 3; k++) {
            System.arraycopy(board[k], 0, this.board[k], 0, 3);
        }
        pre_i = i;
        pre_j = j;
        this.alpha = Game.UNKNOWN_INT;
        board[i][j] = 0;
    }


    @Override
    public void evaluateF() {//评估函数
        if (_F != null) return;
        //computer win
        if (isWin()) _F = Game.MIN_INT;
        else {
            //预测杀局
            predictDeath();
            if (_F == null) super.evaluateF();
        }

    }

    //重置节点的一些数据，消去对再次访问的影响
    @Override
    void reset() {
        alpha = Game.UNKNOWN_INT;
        super.reset();
    }

    @Override
    void play(int depth, int parentAlpha, int parentBeta) {
//        printBoard(board);
        reset();
        if (isWin() || isFull() || depth == 0) {
            evaluateF();
//            System.out.println("evaluate F:"+_F);
            return;
        }

        extend();
        //判断当前局面
        predictDeath();
        //走一步就胜利
        if (_F != null && _F == Game.MIN_INT) {
            for (Node minNode : childNodes) {
                if (minNode.isWin()) {
                    nextNode = minNode;
                    break;
                }
            }
            return;
        }
        for (Node minNode : childNodes) {

            minNode.play(depth - 1, parentAlpha, parentBeta);

            //倒推alpha值(alpha will be bigger)

            if (alpha != Game.UNKNOWN_INT && alpha <= minNode._F || alpha == Game.UNKNOWN_INT) {
                //TODO set next node
                //增加对值相等情况的判断
                if (alpha == minNode._F) {
                    minNode.predictDeath();
                    //死局
                    if (minNode._F != null && minNode._F == Game.MAX_INT) {
                        _F = Game.MAX_INT;
                        nextNode = minNode;
                        return;
                    } else continue;
                }
                nextNode = minNode;
                alpha = minNode._F;
                //成杀局
                if (alpha == Game.MAX_INT) {
                    break;
                }
                if (parentAlpha == Game.UNKNOWN_INT) {
                    parentAlpha = alpha;
//                    System.out.println("update parentAlpha:"+parentAlpha);
                } else if (parentAlpha < alpha) {
                    parentAlpha = alpha;
                }
//                System.out.println("update alpha:"+alpha);
            }
            //beta cut
            if (parentBeta != Game.UNKNOWN_INT && alpha >= parentBeta) {
//                System.out.println("beta cut:"+alpha+">="+parentBeta+" depth: "+depth);
                break;
            }
        }
        _F = alpha;
//        System.out.println("no cut set max F:"+_F+" depth: "+depth);
    }

    @Override
    void extend() {
        if (childNodes == null) {
            childNodes = new LinkedList<Node>();

            //优化初始个数为0的扩展方式
            if (getChessCount() == 0) {
                childNodes.add(new MinNode(board, 0, 0));
                childNodes.add(new MinNode(board, 1, 0));
                childNodes.add(new MinNode(board, 1, 1));
                return;
            }

            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    if (this.board[i][j] == 0) {
                        childNodes.add(new MinNode(board, i, j));
                    }
                }
            }
        }
    }

    @Override
    void predictDeath() {
        int count = getPlayerVitalCount();
        //player go will win
        if (count > 0) _F = Game.MAX_INT;
        else {
            count = getComputerVitalCount();
            //computer will win
            if (count > 1) _F = Game.MIN_INT;
        }
    }
}
